﻿#pragma once
#include <cstddef>
#include <cstdint>
#include <stdio.h>
#include <string>

#include "DiagnosticBag.hpp"
#include "Syntax/Token.hpp"
#include "Syntax/keyword.hpp"
#include "Text/SourceText.hpp"
#include "Text/TextSpan.hpp"

// 词法;
class LexicalScanner
{
public:
    LexicalScanner(SourceText text) : Text(text), currentCodeIndex(0), allKeyword() //, currentRows(0), currentColumns(0)
    {
        this->diagnostics = std::make_shared<DiagnosticBag>();

        codeTotalLength   = this->Text.GetLength();
    };
    // 取出一个令牌;
    SharedToken NextToken();

    // 诊断信息;
    SharedDiagnosticBag Diagnostics() { return this->diagnostics; }

private:
    // 获取当前字符,并前进;
    char NextChar();
    // 获取当前字符,不前进;
    char Current();

    // 后退一个字节;
    inline void Retreat() { this->currentCodeIndex--; };
    // 消耗掉一个字符;
    inline void Advance() { this->currentCodeIndex++; };

    // 获取当前位置;
    inline size_t GetCurrentPosition() { return this->currentCodeIndex; }
    // 空白符号;
    inline bool IsWhitespace(char c) { return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'); }
    // 数字;
    inline bool IsDigit(char c)
    {
        if (c >= '0' && c <= '9')
            return true;
        return false;
    }
    // 标识符;
    inline bool isIdentifier(char c)
    {
        if (c == '_' || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
            return true;
        return false;
    }

    // 截取当前令牌字符串;
    std::string GetCurrentTokenString(size_t textStart)
    {
        size_t      textLength = this->GetCurrentPosition() - textStart;
        std::string text       = this->Text.ToString(textStart, textLength);
        return text;
    }

private:
    // 注释;
    bool ReadComments(char ch);

    //  数字 [ 16 ，8 ，2]; 
    int64_t ReadNumbers();

    // 字符串;
    std::string ReadStrings();

private:
    // 关键字;
    Keyword allKeyword;

    // 代码;
    SourceText Text;

    // 代码字符串-实际长度;
    size_t codeTotalLength;

    // 当前字符所在位置;
    size_t currentCodeIndex;

    // 诊断;
    SharedDiagnosticBag diagnostics;
};
